libostree: Allow OstreeAsyncProgress:status to be set atomically
authorPhilip Withnall <withnall@endlessm.com>
Fri, 28 Apr 2017 18:04:29 +0000 (19:04 +0100)
committerAtomic Bot <atomic-devel@projectatomic.io>
Sat, 29 Apr 2017 11:50:15 +0000 (11:50 +0000)
Rework how the status is handled in OstreeAsyncProgress so that it’s now
a well-known key in the hash table. This means that it can be retrieved
and set atomically with other keys using
ostree_async_progress_[get|set]().

The behaviour of ostree_async_progress_[get|set]_status() is preserved,
with the caveat that `status` can now also be accessed using the other
API on OstreeAsyncProgress, and has to be accessed with the right
GVariant type.

Internally, a NULL status is represented by an empty status string
(since ostree_async_progress_[get|set]_variant() deliberately don’t
allow NULL variants to be set against keys, since that would break the
ostree_async_progress_get() API).

Signed-off-by: Philip Withnall <withnall@endlessm.com>
Closes: #819
Approved by: cgwalters

src/libostree/ostree-async-progress.c

index 4927a9dedf87fb6b41406839f1b40466c1dd6acf..95556814df74322d157eafd0973f99b54ad3ce62 100644 (file)
  * handles thread safety, ensuring that the progress change
  * notification occurs in the thread-default context of the calling
  * operation.
+ *
+ * The ostree_async_progress_get_status() and ostree_async_progress_set_status()
+ * methods get and set a well-known `status` key of type %G_VARIANT_TYPE_STRING.
+ * This key may be accessed using the other #OstreeAsyncProgress methods, but it
+ * must always have the correct type.
  */
 
 enum {
@@ -58,8 +63,6 @@ struct OstreeAsyncProgress
   GHashTable *values;  /* (element-type uint GVariant) */
 
   gboolean dead;
-
-  char *status;
 };
 
 G_DEFINE_TYPE (OstreeAsyncProgress, ostree_async_progress, G_TYPE_OBJECT)
@@ -75,7 +78,6 @@ ostree_async_progress_finalize (GObject *object)
   g_clear_pointer (&self->maincontext, g_main_context_unref);
   g_clear_pointer (&self->idle_source, g_source_unref);
   g_hash_table_unref (self->values);
-  g_free (self->status);
 
   G_OBJECT_CLASS (ostree_async_progress_parent_class)->finalize (object);
 }
@@ -243,28 +245,47 @@ ensure_callback_locked (OstreeAsyncProgress *self)
   g_source_attach (self->idle_source, self->maincontext);
 }
 
+/**
+ * ostree_async_progress_set_status:
+ * @self: an #OstreeAsyncProgress
+ * @status: (nullable): new status string, or %NULL to clear the status
+ *
+ * Set the human-readable status string for the #OstreeAsyncProgress. This
+ * operation is thread-safe. %NULL may be passed to clear the status.
+ *
+ * This is a convenience function to set the well-known `status` key.
+ *
+ * Since: 2017.6
+ */
 void
 ostree_async_progress_set_status (OstreeAsyncProgress       *self,
                                   const char                *status)
 {
-  g_mutex_lock (&self->lock);
-  if (!self->dead)
-    {
-      g_free (self->status);
-      self->status = g_strdup (status);
-      ensure_callback_locked (self);
-    }
-  g_mutex_unlock (&self->lock);
+  ostree_async_progress_set_variant (self, "status",
+                                     g_variant_new_string ((status != NULL) ? status : ""));
 }
 
+/**
+ * ostree_async_progress_get_status:
+ * @self: an #OstreeAsyncProgress
+ *
+ * Get the human-readable status string from the #OstreeAsyncProgress. This
+ * operation is thread-safe. The retuned value may be %NULL if no status is
+ * set.
+ *
+ * This is a convenience function to get the well-known `status` key.
+ *
+ * Returns: (transfer full) (nullable): the current status, or %NULL if none is set
+ * Since: 2017.6
+ */
 char *
 ostree_async_progress_get_status (OstreeAsyncProgress       *self)
 {
-  char *ret;
-  g_mutex_lock (&self->lock);
-  ret = g_strdup (self->status);
-  g_mutex_unlock (&self->lock);
-  return ret;
+  g_autoptr(GVariant) rval = ostree_async_progress_get_variant (self, "status");
+  const gchar *status = (rval != NULL) ? g_variant_get_string (rval, NULL) : NULL;
+  if (status != NULL && *status == '\0')
+    status = NULL;
+  return g_strdup (status);
 }
 
 /**